package com.liuliu.config;

import com.liuliu.filter.JwtAuthenticationTokenFilter;
import com.liuliu.handler.LiuSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

@Configuration //配置类
@EnableWebSecurity // 开启Spring Security的功能 代替了 implements WebSecurityConfigurerAdapter
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;
    @Autowired
    private AccessDeniedHandler accessDeniedHandler;
    @Autowired
    private AuthenticationSuccessHandler successHandler;

    @Autowired
    private AuthenticationFailureHandler failureHandler;


    @Autowired
    private LogoutSuccessHandler logoutSuccessHandler;
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }




    /**
     *
     * 认证相关的配置都在这个2里面进行配置
     * 配置Spring Security的过滤链。
     *
     * @param http 用于构建安全配置的HttpSecurity对象。
     * @return 返回配置好的SecurityFilterChain对象。
     * @throws Exception 如果配置过程中发生错误，则抛出异常。
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // 配置自定义成功后的处理 认证成功后会调用这个方法
//        http.formLogin()
//                .successHandler(successHandler)
//                //配置认证失败处理器
//                .failureHandler(failureHandler);
//
//        //配置登出自定义处理器
//        http.logout().logoutSuccessHandler(logoutSuccessHandler);


//   这个路劲和自定义接口进行拦截一起使用，不和下面的进行处理     http.authorizeRequests().anyRequest().authenticated();

        http
                // 禁用CSRF保护
                .csrf(csrf -> csrf.disable())
                // 设置会话创建策略为无状态 不通过session获取securityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                // 配置授权规则   指定user/login路径.允许匿名访问(未登录可访问已登陆不能访问). 其他路径需要身份认证
                .authorizeRequests()
                .antMatchers("/user/login").anonymous()
                // 自定义配置权限，访问这个接口的时候，需要拥有sys下面这个权限 当前登录人
                .antMatchers("/testCors").hasAuthority("system:menu:list")
                // 除上面的接口外都需要鉴权
                .anyRequest().authenticated();





        //设置过滤器jwtAuthenticationTokenFilter在校验账密过滤器之前
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);


        //2.关于认证过程中抛出的某些异常 例如：if (Objects.isNull(authenticate)){
        //            throw new RuntimeException("用户名或密码错误！");
        //        }，这个是无效的，他过滤器里面的异常处理器捕获了，不会抛出，可以在后面的自定义异常处理器中获取出来返给前端，最好不要写死，authException.getMessage() 这样就行；
        // 配置异常处理器
        http.exceptionHandling()
                //配置认证失败异常处理
                .authenticationEntryPoint(authenticationEntryPoint)
                //配置授权失败 权限不足的异常处理
                .accessDeniedHandler(accessDeniedHandler);

        // 允许跨域
        http.cors();




    }


}